using System;
using System.Collections.Generic;
using System.IO;
using GameFramework;
using UnityEditor;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace StarForce.Editor
{
    public class UIFormCodeGenerator : EditorWindow
    {
        private enum GenCodeType
        {
            UIForm,
            UIItem,
        }

        private enum CodeType
        {
            Normal,
            Hotfix,
        }

        [SerializeField] private List<GameObject> m_GameObjects = new List<GameObject>();

        private SerializedObject m_SerializedObject;
        
        private SerializedProperty m_SerializedProperty;

        /// <summary>
        /// 生成实体类型
        /// </summary>
        private GenCodeType m_GenCodeType;
        
        /// <summary>
        /// 代码类型
        /// </summary>
        private CodeType m_CodeType= CodeType.Hotfix;

        /// <summary>
        /// 是否生成主体逻辑代码
        /// </summary>
        private bool m_IsGenMainLogicCode = true;

        /// <summary>
        /// 是否生成自动绑定组件代码
        /// </summary>
        private bool m_IsGenAutoBindCode = true;

        /// <summary>
        /// 实体界面逻辑代码位置
        /// </summary>Assets/GameMain/Scripts/UI/UILogic
        private const string UIFormCodePath = "Assets/GameMain/Scripts/UI/UILogic/UIForm";

        /// <summary>
        /// uiitem逻辑代码位置
        /// </summary>
        private const string UIItemCodePath = "Assets/GameMain/Scripts/UI/UILogic/UIItem";
        
        /// <summary>
        /// 界面元素绑定代码位置
        /// </summary>
        private const string UIBiddingCodePath = "Assets/GameMain/Scripts/UI/UILogic/BindComponents";
        
        /// <summary>
        /// 热更实体界面逻辑代码位置
        /// </summary>Assets/GameMain/Scripts/UI/UILogic
        private const string HotfixUIFormCodePath = "Assets/Hotfix/UI/UILogic/UIForm";

        /// <summary>
        /// 热更uiitem逻辑代码位置
        /// </summary>
        private const string HotfixUIItemCodePath = "Assets/Hotfix/UI/UILogic/UIItem";
        
        /// <summary>
        /// 热更界面元素绑定代码位置
        /// </summary>
        private const string HotfixUIBiddingCodePath = "Assets/Hotfix/UI/UILogic/BindComponents";
        
        

        [MenuItem("Star Force/代码生成器/实体与界面代码生成器")]
        public static void OpenCodeGeneratorWindow()
        {
            UIFormCodeGenerator window = GetWindow<UIFormCodeGenerator>(true, "实体与界面代码生成器");
            window.minSize = new Vector2(300f, 300f);
        }

        private void OnEnable()
        {
            m_SerializedObject = new SerializedObject(this);
            m_SerializedProperty = m_SerializedObject.FindProperty("m_GameObjects");
        }

        private void OnGUI()
        {
            //绘制GameObject列表
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(m_SerializedProperty, true);
            if (EditorGUI.EndChangeCheck())
            {
                m_SerializedObject.ApplyModifiedProperties();
            }

            //绘制自动生成代码类型的弹窗
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("自动生成的代码类型：", GUILayout.Width(140f));
            m_GenCodeType = (GenCodeType) EditorGUILayout.EnumPopup(m_GenCodeType, GUILayout.Width(100f));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("项目类型：", GUILayout.Width(140f));
            m_CodeType = (CodeType) EditorGUILayout.EnumPopup(m_CodeType, GUILayout.Width(100f));
            EditorGUILayout.EndHorizontal();
            //绘制代码生成路径文本
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("自动生成的代码路径：", GUILayout.Width(140f));

            switch (m_GenCodeType)
            {
                case GenCodeType.UIForm:
                    EditorGUILayout.LabelField(UIFormCodePath);
                    break;
                case GenCodeType.UIItem:
                    EditorGUILayout.LabelField(UIItemCodePath);
                    break;
            }

            EditorGUILayout.EndHorizontal();


            m_IsGenMainLogicCode = GUILayout.Toggle(m_IsGenMainLogicCode, "生成主体逻辑代码");

            EditorGUILayout.BeginHorizontal();

            m_IsGenAutoBindCode = GUILayout.Toggle(m_IsGenAutoBindCode, "生成自动绑定组件代码", GUILayout.Width(150f));

            EditorGUILayout.EndHorizontal();

            //绘制生成代码的按钮
            if (GUILayout.Button("生成代码", GUILayout.Width(100f)))
            {
                if (m_GameObjects.Count == 0)
                {
                    EditorUtility.DisplayDialog("警告", "请选择实体或界面的游戏物体", "OK");
                    return;
                }

                switch (m_CodeType)
                {
                    case CodeType.Normal : 
                        if (m_GenCodeType == GenCodeType.UIForm)
                        {
                            GenUIFormCode();
                        }
                        else
                        {
                            GenUIItemCode();
                        }
                        break;
                    case CodeType.Hotfix : 
                        if (m_GenCodeType == GenCodeType.UIForm)
                        {
                            GenHotfixUIFormCode();
                        }
                        else
                        {
                            GenHotfixUIItemCode();
                        }
                        break;
                    
                }
                AssetDatabase.Refresh();
                EditorUtility.DisplayDialog("提示", "代码生成完毕", "OK");
            }
        }

        /// <summary>
        /// 生成UIform
        /// </summary>
        private void GenUIFormCode()
        {
            string codepath = UIFormCodePath;
            string nameSpace = Utility.Text.Format("{0}", Constant.AssemblyInfo.Namespace);
            string logicBaseClass = "UGuiForm";
            string bindPath = $"{UIBiddingCodePath}/UIForm/";

            foreach (GameObject go in m_GameObjects)
            {
                if (m_IsGenMainLogicCode)
                {
                    GenUIFormMainLogicCode(codepath, go, nameSpace, logicBaseClass);
                }

                if (m_IsGenAutoBindCode)
                {
                    GenAutoBindCode(bindPath, go, nameSpace);
                }
            }
        }
        /// <summary>
        /// 生成热更UIform
        /// </summary>
        private void GenHotfixUIFormCode()
        {
            string codepath = HotfixUIFormCodePath;
            string nameSpace = Utility.Text.Format("{0}", Constant.AssemblyInfo.HotfixNamespace);
            string logicBaseClass = "HotfixUGuiForm";
            string bindPath = $"{HotfixUIBiddingCodePath}/UIForm/";

            foreach (GameObject go in m_GameObjects)
            {
                if (m_IsGenMainLogicCode)
                {
                    GenHotfixUIFormMainLogicCode(codepath, go, nameSpace, logicBaseClass);
                }

                if (m_IsGenAutoBindCode)
                {
                    GenAutoBindCode(bindPath, go, nameSpace);
                }
            }
        }
         /// <summary>
        /// 生成热更页面逻辑代码
        /// </summary>
        /// <param name="codePath"></param>
        /// <param name="go"></param>
        /// <param name="nameSpace"></param>
        /// <param name="logicBaseClass"></param>
        private void GenHotfixUIFormMainLogicCode(string codePath, GameObject go, string nameSpace, string logicBaseClass)
        {
            string initParam = string.Empty;
            
            string baseInitParam = string.Empty;
            
            string accessModifier = "protected";

            initParam = Utility.Text.Format("{0}.HotfixUGuiForm uiFormLogic,",Constant.AssemblyInfo.Namespace);
            baseInitParam = "uiFormLogic, ";
            accessModifier = "public";
            

            if (!Directory.Exists($"{codePath}/"))
            {
                Directory.CreateDirectory($"{codePath}/");
            }

            using (StreamWriter sw = new StreamWriter($"{codePath}/{go.name}.cs"))
            {
                sw.WriteLine("using System.Collections;");
                sw.WriteLine("using System.Collections.Generic;");
                sw.WriteLine("using UnityEngine;");
                sw.WriteLine("");
                sw.WriteLine("//自动生成于：" + DateTime.Now);

                //命名空间
                sw.WriteLine("namespace " + nameSpace);
                sw.WriteLine("{");
                sw.WriteLine("");

                //类名
                sw.WriteLine($"\tpublic partial class {go.name} : {logicBaseClass}");
                sw.WriteLine("\t{");
                sw.WriteLine("");

                //OnInit
                sw.WriteLine($"\t\t{accessModifier} override void OnInit({initParam}object userdata)");
                sw.WriteLine("\t\t{");
                sw.WriteLine($"\t\t\tbase.OnInit({baseInitParam}userdata);");
                sw.WriteLine("");
                sw.WriteLine($"\t\t\tGetBindComponents(uiFormLogic.gameObject);");
                sw.WriteLine("\t\t}");
                sw.WriteLine("\t}");
                sw.WriteLine("}");
            }
        }

        /// <summary>
        /// 生成页面逻辑代码
        /// </summary>
        /// <param name="codePath"></param>
        /// <param name="go"></param>
        /// <param name="nameSpace"></param>
        /// <param name="logicBaseClass"></param>
        private void GenUIFormMainLogicCode(string codePath, GameObject go, string nameSpace, string logicBaseClass)
        {
            string initParam = string.Empty;

            string baseInitParam = string.Empty;

            string accessModifier = "protected";

//            initParam = Utility.Text.Format("{0}.HotfixUGuiForm uiFormLogic,", Constant.AssemblyInfo.Namespace);
//            baseInitParam = "uiFormLogic, ";
//            accessModifier = "public";


            if (!Directory.Exists($"{codePath}/"))
            {
                Directory.CreateDirectory($"{codePath}/");
            }

            using (StreamWriter sw = new StreamWriter($"{codePath}/{go.name}.cs"))
            {
                sw.WriteLine("using System.Collections;");
                sw.WriteLine("using System.Collections.Generic;");
                sw.WriteLine("using UnityEngine;");
                sw.WriteLine("");
                sw.WriteLine("//自动生成于：" + DateTime.Now);

                //命名空间
                sw.WriteLine("namespace " + nameSpace);
                sw.WriteLine("{");
                sw.WriteLine("");

                //类名
                sw.WriteLine($"\tpublic partial class {go.name} : {logicBaseClass}");
                sw.WriteLine("\t{");
                sw.WriteLine("");

                //OnInit
                sw.WriteLine($"\t\t{accessModifier} override void OnInit({initParam}object userdata)");
                sw.WriteLine("\t\t{");
                sw.WriteLine($"\t\t\tbase.OnInit({baseInitParam}userdata);");
                sw.WriteLine("");
                sw.WriteLine($"\t\t\tGetBindComponents(gameObject);");
                sw.WriteLine("\t\t}");
                sw.WriteLine("\t}");
                sw.WriteLine("}");
            }
        }

        /// <summary>
        /// 生成页面组件绑定代码
        /// </summary>
        /// <param name="codePath"></param>
        /// <param name="go"></param>
        /// <param name="nameSpace"></param>
        /// <param name="nameEx"></param>
        private void GenAutoBindCode(string codePath, GameObject go, string nameSpace, string nameEx = "")
        {
            ComponentAutoBindTool bindTool = go.GetComponent<ComponentAutoBindTool>();
            if (bindTool == null)
            {
                return;
            }

            if (!Directory.Exists(codePath))
            {
                Directory.CreateDirectory(codePath);
            }

            using (StreamWriter sw = new StreamWriter($"{codePath}/{go.name}{nameEx}.BindComponents.cs"))
            {
                sw.WriteLine("using UnityEngine;");
//                if (m_GenCodeType == GenCodeType.UIForm)
//                {
                sw.WriteLine("using UnityEngine.UI;");
//                }
                sw.WriteLine("");

                sw.WriteLine("//自动生成于：" + DateTime.Now);

                //命名空间
                sw.WriteLine("namespace " + nameSpace);
                sw.WriteLine("{");
                sw.WriteLine("");

                //类名
                sw.WriteLine($"\tpublic partial class {go.name}{nameEx}");
                sw.WriteLine("\t{");
                sw.WriteLine("");


                foreach (ComponentAutoBindTool.BindData data in bindTool.BindDatas)
                {
                    sw.WriteLine($"\t\tprivate {data.BindCom.GetType().Name} m_{data.Name};");
                }

                sw.WriteLine("");

                sw.WriteLine("\t\tprivate void GetBindComponents(GameObject go)");
                sw.WriteLine("\t\t{");

                //获取绑定的组件
                sw.WriteLine($"\t\t\tComponentAutoBindTool autoBindTool = go.GetComponent<ComponentAutoBindTool>();");
                sw.WriteLine("");

                //根据索引获取

                for (int i = 0; i < bindTool.BindDatas.Count; i++)
                {
                    ComponentAutoBindTool.BindData data = bindTool.BindDatas[i];
                    string filedName = $"m_{data.Name}";
                    sw.WriteLine(
                        $"\t\t\t{filedName} = autoBindTool.GetBindComponent<{data.BindCom.GetType().Name}>({i});");
                }


                sw.WriteLine("\t\t}");

                sw.WriteLine("");

                sw.WriteLine("\t}");

                sw.WriteLine("}");
            }
        }


        /// <summary>
        /// 生成item代码
        /// </summary>
        private void GenUIItemCode()
        {
            string codepath = UIItemCodePath;
            string nameSpace = Utility.Text.Format("{0}", Constant.AssemblyInfo.Namespace);
            string logicBaseClass = "ItemContext";
            string bindPath = $"{UIBiddingCodePath}/UIItem/";

            foreach (GameObject go in m_GameObjects)
            {
                if (m_IsGenMainLogicCode)
                {
                    GenUIMainItemCode(codepath, go, nameSpace, logicBaseClass);
                }

                if (m_IsGenAutoBindCode)
                {
                    GenUIItemBindCode(bindPath, go, nameSpace);
                }
            }
        }
        
        /// <summary>
        /// 生成热更item代码
        /// </summary>
        private void GenHotfixUIItemCode()
        {
            string codepath = HotfixUIItemCodePath;
            string nameSpace = Utility.Text.Format("{0}", Constant.AssemblyInfo.HotfixNamespace);
            string logicBaseClass = "ItemContext";
            string bindPath = $"{HotfixUIBiddingCodePath}/UIItem/";

            foreach (GameObject go in m_GameObjects)
            {
                if (m_IsGenMainLogicCode)
                {
                    GenUIMainItemCode(codepath, go, nameSpace, logicBaseClass);
                }

                if (m_IsGenAutoBindCode)
                {
                    GenUIItemBindCode(bindPath, go, nameSpace);
                }
            }
        }

        /// <summary>
        /// 生成Item主体逻辑代码
        /// </summary>
        /// <param name="codePath"></param>
        /// <param name="go"></param>
        /// <param name="nameSpace"></param>
        /// <param name="logicBaseClass"></param>
        private void GenUIMainItemCode(string codePath, GameObject go, string nameSpace, string logicBaseClass)
        {
            string initParam = string.Empty;

            string baseInitParam = string.Empty;

            string accessModifier = "protected";

//            initParam = Utility.Text.Format("{0}.HotfixUGuiForm uiFormLogic,", Constant.AssemblyInfo.Namespace);
//            baseInitParam = "uiFormLogic, ";
            accessModifier = "public";


            if (!Directory.Exists($"{codePath}/"))
            {
                Directory.CreateDirectory($"{codePath}/");
            }

            using (StreamWriter sw = new StreamWriter($"{codePath}/{go.name}.cs"))
            {
                sw.WriteLine("using System.Collections;");
                sw.WriteLine("using System.Collections.Generic;");
                sw.WriteLine("using UnityEngine;");
                sw.WriteLine("");
                sw.WriteLine("//自动生成于：" + DateTime.Now);

                //命名空间
                sw.WriteLine("namespace " + nameSpace);
                sw.WriteLine("{");
                sw.WriteLine("");

                //类名
                sw.WriteLine($"\tpublic partial class {go.name} : {logicBaseClass}");
                sw.WriteLine("\t{");
                sw.WriteLine("");

                //OnInit
                sw.WriteLine($"\t\t{accessModifier} override void Init()");
                sw.WriteLine("\t\t{");
//                sw.WriteLine($"\t\t\tbase.Init();");
                sw.WriteLine("");
//                sw.WriteLine($"\t\t\tGetBindComponents();");
                sw.WriteLine("\t\t}");
                sw.WriteLine("\t}");
                sw.WriteLine("}");
            }
        }



        /// <summary>
        /// 生成item绑定代码
        /// </summary>
        /// <param name="codePath"></param>
        /// <param name="go"></param>
        /// <param name="nameSpace"></param>
        /// <param name="logicBaseClass"></param>
        private void GenUIItemBindCode(string codePath, GameObject go, string nameSpace, string nameEx = "")
        {
            ComponentAutoBindTool bindTool = go.GetComponent<ComponentAutoBindTool>();
            if (bindTool == null)
            {
                return;
            }

            if (!Directory.Exists(codePath))
            {
                Directory.CreateDirectory(codePath);
            }

            using (StreamWriter sw = new StreamWriter($"{codePath}/{go.name}{nameEx}.BindComponents.cs"))
            {
                sw.WriteLine("using UnityEngine;");
//                if (m_GenCodeType == GenCodeType.UIForm)
//                {
                sw.WriteLine("using UnityEngine.UI;");
//                }
                sw.WriteLine("");

                sw.WriteLine("//自动生成于：" + DateTime.Now);

                //命名空间
                sw.WriteLine("namespace " + nameSpace);
                sw.WriteLine("{");
                sw.WriteLine("");

                //类名
                sw.WriteLine($"\tpublic partial class {go.name}{nameEx}");
                sw.WriteLine("\t{");
                sw.WriteLine("");
                foreach (ComponentAutoBindTool.BindData data in bindTool.BindDatas)
                {
                    sw.WriteLine($"\t\tprivate {data.BindCom.GetType().Name} m_{data.Name};");
                }
                sw.WriteLine("");
                foreach (ComponentAutoBindTool.BindData data in bindTool.BindDatas)
                {
                    string proName = data.Name.Split('_')[1];
                    sw.WriteLine($"\t\tpublic {data.BindCom.GetType().Name} {proName}");
                    sw.WriteLine("\t\t{");
                    sw.WriteLine("\t\t\tget");
                    sw.WriteLine("\t\t\t{");
                    sw.WriteLine($"\t\t\t\t return m_{data.Name};");
                    sw.WriteLine("\t\t\t}");
                    sw.WriteLine("\t\t\tset");
                    sw.WriteLine("\t\t\t{");
                    sw.WriteLine($"\t\t\t\t m_{data.Name} = value;");
                    sw.WriteLine("\t\t\t}");
                    sw.WriteLine("\t\t}");
                }
                sw.WriteLine("");

                sw.WriteLine("\t\tpublic override void GetBindComponents()");
                sw.WriteLine("\t\t{");

                //获取绑定的组件
                sw.WriteLine($"\t\t\tComponentAutoBindTool autoBindTool = GameObject.GetComponent<ComponentAutoBindTool>();");
                sw.WriteLine("");

                //根据索引获取

                for (int i = 0; i < bindTool.BindDatas.Count; i++)
                {
                    ComponentAutoBindTool.BindData data = bindTool.BindDatas[i];
                    string filedName = $"m_{data.Name}";
                    sw.WriteLine(
                        $"\t\t\t{filedName} = autoBindTool.GetBindComponent<{data.BindCom.GetType().Name}>({i});");
                }
                sw.WriteLine("");
                sw.WriteLine($"\t\t\tInit();");

                sw.WriteLine("\t\t}");

                sw.WriteLine("");

                sw.WriteLine("\t}");

                sw.WriteLine("}");
            }
        }
    }
}

